home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Explosion
/
Software Explosion (Fore-Matt Home Computing)(1996).iso
/
games
/
workbench
/
blackjack_ii
/
source.lha
/
source
/
jack.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-24
|
39KB
|
1,286 lines
/*
* Jack v2.1
* $VER: jack.c 2.1 (08.20.94)
*
* written by John Corigliano with SAS/C 6.51
*
* Copyright 1994 John Corigliano
*
* internet: j.corigliano@genie.geis.com
* mopp@bix.com
* j_mopp@delphi.com
*
* GEnie: J.CORIGLIANO
* bix: mopp
* Delphi: j_mopp
*
*/
#define __USE_SYSBASE /* SAS/C - use Absolute Exec Base = 4 */
long __oslibversion = 37L; /* SAS/C - auotinit, WB 2.04 please */
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <exec/memory.h>
#include <exec/lists.h>
#include <exec/nodes.h>
#include <exec/ports.h>
#include <graphics/gfx.h>
#include <graphics/gfxbase.h>
#include <graphics/gfxmacros.h>
#include <libraries/gadtools.h>
#include <dos/dos.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <float.h>
#include <proto/intuition.h>
#include <proto/gadtools.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/dos.h>
#include "jack.h" /* Holds card image structures */
#ifdef LATTICE
int CXBRK(void) { return(0); }
int chkabort(void) { return(0); }
#endif
/* Macros */
#define GAD_BUF(X) ((struct StringInfo *)X->SpecialInfo)->Buffer
#define GAD_OFF(X) if (!(X->Flags & GFLG_DISABLED)) \
GT_SetGadgetAttrs(X,win,NULL,GA_Disabled,TRUE,TAG_END)
#define GAD_ON(X) if (X->Flags & GFLG_DISABLED) \
GT_SetGadgetAttrs(X,win,NULL,GA_Disabled,FALSE,TAG_END)
#define MASK 0x0F
#define REQ_OK 0
#define REQ_ASK 1
/* Gadget IDs */
#define HIT_GAD 0
#define STICK_GAD 1
#define DD_GAD 2
#define SUR_GAD 3
#define DEAL_GAD 4
#define BET_GAD 5
#define MAX_CARDS 416 /* 8 decks */
#define A_DECK 52 /* 52 cards per deck */
#define BOX_WIDTH 146 /* decks gauge x-size */
#define BOX_HEIGHT 9 /* decks gauge y-size */
#define BOX_LEFT 179 /* decks gauge left edge */
#define BOX_TOP (114 + win_offset)
#define P_ROW (4 + win_offset)
#define D_ROW (66 + win_offset)
#define COL_1 13 /* Col to put first card */
#define COL_2 74 /* Col to put second cards */
#define CARD_WIDTH 60 /* Pixels */
#define CARD_HEIGHT 40 /* Pixels */
#define PLAYER 0x0 /* An ID */
#define DEALER 0x1 /* An ID */
#define FIRST 0x2 /* Playing dealer's hole card */
#define BACK 0x3 /* Playing split card */
/* My function prototypes */
VOID openWindow(VOID);
BOOL checkBet(VOID);
VOID doIDCMP(VOID);
VOID closer(VOID);
VOID printBank(VOID);
VOID gauge(VOID);
VOID drawCard(struct Card *, UWORD, UWORD);
VOID allocDeck(VOID);
VOID shuffle(VOID);
BOOL initDeal(VOID);
VOID addScore(UBYTE, UBYTE *);
VOID addCard(VOID);
VOID printScore(VOID);
VOID printWins(VOID);
VOID dealsTurn(VOID);
VOID wText(UBYTE *);
VOID playBack(VOID);
VOID openStatWin(VOID);
VOID safeCloseWin(struct Window *);
VOID refreshStatWin(VOID);
VOID showStats(VOID);
BOOL putReq(UBYTE *, UBYTE *, BYTE);
UBYTE ver[] = {"$VER: Jack 2.1 (08.20.94"};
struct Card **deck = NULL, *hole_card, *backcard;
UWORD dealt = 0, p_cord;
UBYTE num_decks = 1, old_decks = 1, t_decks = 0;
UBYTE p_score, p_score2, d_score;
UBYTE p_crd[13], d_crd[13], p_hand[16], d_hand[16];
FLOAT bank = 100, betA = 10, betB = 0, ins = 0, bet_main = 10, win_p = 0;
UBYTE win_offset;
UWORD ySize, hands = 0, winners = 0;
BOOL start_stats = FALSE, use_delay = TRUE;
struct Window *win = NULL, *stat_win = NULL;
struct Gadget *glist = NULL, *gads[6];
struct TextAttr Topaz80 = {"topaz.font", 8, 0, 0,};
struct TextFont *wFont = NULL;
VOID *vi = NULL;
struct Menu *strip;
struct MsgPort *mport = NULL;
/*
*main() proccesses the args, opens the window,
* and calls the IDCMP loop.
*/
main(int argc, char **argv)
{
/* If run from WB, SAS/C handles startup and sets these values */
if (!argc) {
argc = _WBArgc;
argv = _WBArgv;
}
/* Parse args */
while (--argc) {
if (!strcmp("STATS", argv[argc]))
start_stats = TRUE;
else if (!strncmp("BANK=", argv[argc], 5)) {
bank = atof(&argv[argc][5]);
if (bank < 0.10) bank = 100.00;
if (bank > (FLT_MAX / 2)) bank = 100;
}
else if (!strncmp("DECKS=", argv[argc], 6))
num_decks = old_decks = atoi(&argv[argc][6]);
else if (!strcmp("NODELAY", argv[argc]))
use_delay = FALSE;
}
openWindow();
doIDCMP();
closer();
}
/*
* Clean up routine that can be called at any point in the program. It
* frees memory, closes the window, frees menus and gadgets, removes
* the message port.
*/
VOID closer(VOID)
{
if (deck) FreeMem(deck, sizeof(struct Card *) * A_DECK * num_decks);
if (strip) {
ClearMenuStrip(win);
FreeMenus(strip);
}
if (stat_win) safeCloseWin(stat_win);
if (win) safeCloseWin(win);
if (wFont) CloseFont(wFont);
if (vi) FreeVisualInfo(vi);
if (mport) DeletePort(mport);
if (glist) FreeGadgets(glist);
exit(0);
}
/*
* Open the window with gadgets and menus. Note: the window has no IDCMP
* flags set. This is done so that Intuition will not create a message
* port for this window. doIDCMP() creates the port for this win.
*/
VOID openWindow(VOID)
{
struct NewMenu nm[] = {
{ NM_TITLE, "Game", 0,0,0,0,},
{ NM_ITEM, "Decks", 0,0,0,0,},
{ NM_SUB, "1", 0,CHECKIT,~1,0,},
{ NM_SUB, "2", 0,CHECKIT,~2,0,},
{ NM_SUB, "4", 0,CHECKIT,~4,0,},
{ NM_SUB, "8", 0,CHECKIT,~8,0,},
{ NM_ITEM, "Stats", 0,0,0,0,},
{ NM_SUB, "On", 0,CHECKIT,~1,0,},
{ NM_SUB, "Off", 0,CHECKIT,~2,0,},
{ NM_ITEM, NM_BARLABEL, 0,0,0,0,},
{ NM_ITEM, "Quit", 0,0,0,0,},
{ NM_END, NULL, 0,0,0,0,},
};
struct Screen *scn;
struct Gadget *gad;
struct NewGadget ng;
UWORD win_left;
if (!(scn = LockPubScreen(NULL))) closer();
vi = GetVisualInfo(scn, TAG_END);
win_offset = 1 + scn->WBorTop + scn->Font->ta_YSize;
switch (num_decks ) {
case 1:
nm[2].nm_Flags |= CHECKED;
break;
case 2:
nm[3].nm_Flags |= CHECKED;
break;
case 4:
nm[4].nm_Flags |= CHECKED;
break;
case 8:
nm[5].nm_Flags |= CHECKED;
break;
default:
num_decks = old_decks = 1;
nm[2].nm_Flags |= CHECKED;
break;
}
if (start_stats) nm[7].nm_Flags |= CHECKED;
else nm[8].nm_Flags |= CHECKED;
gad = CreateContext(&glist);
ng.ng_LeftEdge = 127;
ng.ng_TopEdge = 113 + win_offset;
ng.ng_Width = 49;
ng.ng_Height = 13;
ng.ng_GadgetText = "Hit";
ng.ng_TextAttr = &Topaz80;
ng.ng_GadgetID = HIT_GAD;
ng.ng_Flags = NULL;
ng.ng_VisualInfo = vi;
ng.ng_UserData = NULL;
gads[HIT_GAD] = gad = CreateGadget(BUTTON_KIND, gad, &ng,
GA_Disabled, TRUE, TAG_END);
ng.ng_LeftEdge = 78;
ng.ng_TopEdge = 126 + win_offset;
ng.ng_GadgetText = "DD";
ng.ng_GadgetID = DD_GAD;
gads[DD_GAD] = gad = CreateGadget(BUTTON_KIND, gad, &ng,
GA_Disabled, TRUE, TAG_END);
ng.ng_LeftEdge = 127;
ng.ng_TopEdge = 126 + win_offset;
ng.ng_GadgetText = "Stick";
ng.ng_GadgetID = STICK_GAD;
gads[STICK_GAD] = gad = CreateGadget(BUTTON_KIND, gad, &ng,
GA_Disabled, TRUE, TAG_END);
ng.ng_LeftEdge = 78;
ng.ng_TopEdge = 113 + win_offset;
ng.ng_GadgetText = "Srndr";
ng.ng_GadgetID = SUR_GAD;
gads[SUR_GAD] = gad = CreateGadget(BUTTON_KIND, gad, &ng,
GA_Disabled, TRUE, TAG_END);
ng.ng_TopEdge = 126 + win_offset;
ng.ng_LeftEdge = 177;
ng.ng_Width = 150;
ng.ng_GadgetText = "Deal";
ng.ng_GadgetID = DEAL_GAD;
gads[DEAL_GAD] = gad = CreateGadget(BUTTON_KIND, gad, &ng, TAG_END);
ng.ng_LeftEdge = 227;
ng.ng_TopEdge = 141 + win_offset;
ng.ng_Width = 100;
ng.ng_GadgetText = "Wager:";
ng.ng_Flags = PLACETEXT_LEFT;
ng.ng_GadgetID = BET_GAD;
gads[BET_GAD] = gad = CreateGadget(STRING_KIND, gad, &ng,
STRINGA_Justification, GACT_STRINGRIGHT,
GTST_String, "10.00",
TAG_END);
if (!start_stats) win_left = (scn->Width - 332) / 2;
else win_left = (scn->Width - 462) / 2;
if (win = OpenWindowTags(NULL,
WA_Left, win_left,
WA_Top, (scn->Height - (166 + win_offset)) / 2,
WA_Width, 332,
WA_Height, 166 + win_offset,
WA_Activate, TRUE,
WA_CloseGadget, TRUE,
WA_DepthGadget, TRUE,
WA_DragBar, TRUE,
WA_Gadgets, glist,
WA_IDCMP, NULL,
WA_PubScreen, scn,
WA_Title, "⌐1994 John Corigliano",
WA_ScreenTitle, "Black Jack!",
TAG_END)) {
GT_RefreshWindow(win, NULL);
/* Set the window font to "topaz.font", 8 */
wFont = OpenFont(&Topaz80);
SetFont(win->RPort, wFont);
ySize = win->IFont->tf_YSize;
/* Attach menu strip */
strip = CreateMenus(nm, TAG_END);
LayoutMenus(strip, vi, TAG_END);
SetMenuStrip(win, strip);
/* Use GadTools for beveled boxes */
DrawBevelBox(win->RPort, 5, 2 + win_offset, 322, 46,
GT_VisualInfo, vi,
GTBB_Recessed, TRUE, TAG_END);
DrawBevelBox(win->RPort, 5, 50 + win_offset, 322, 12,
GT_VisualInfo, vi,
GTBB_Recessed, TRUE, TAG_END);
DrawBevelBox(win->RPort, 5, 64 + win_offset, 322, 46,
GT_VisualInfo, vi,
GTBB_Recessed, TRUE, TAG_END);
DrawBevelBox(win->RPort, 5, 113 + win_offset, 70, 26,
GT_VisualInfo, vi,
GTBB_Recessed, TRUE, TAG_END);
DrawBevelBox(win->RPort, 177, 113 + win_offset, 150, 12,
GT_VisualInfo, vi,
GTBB_Recessed, TRUE, TAG_END);
SetAPen(win->RPort, 1);
Move(win->RPort, 10, 123 + win_offset);
Text(win->RPort, "You:", 4);
Move(win->RPort, 10, 133 + win_offset);
Text(win->RPort, "Deal:", 5);
printBank();
printWins();
}
UnlockPubScreen(NULL, scn);
if (!win) closer();
return;
}
/*
* Checks to make sure bet is in the proper format (i.e 1.00)
* Also makes sure that the player can cover the bet
*/
BOOL checkBet(VOID)
{
UBYTE bet_str[32], str[32], i;
BOOL format = FALSE;
strcpy(bet_str, GAD_BUF(gads[BET_GAD]));
if (strlen(bet_str) < 3) format = TRUE;
if (!format) {
for (i = 0; i < (strlen(bet_str) - 3); i++)
if (!(isdigit(bet_str[i]))) format = TRUE;
if (bet_str[i++] != '.') format = TRUE;
if (!(isdigit(bet_str[i++]))) format = TRUE;
if (!(isdigit(bet_str[i]))) format = TRUE;
}
if (format) {
DisplayBeep(win->WScreen);
sprintf(str, "Bad format: %s", bet_str);
wText(str);
bet_main = betA = 0;
ActivateGadget(gads[BET_GAD], win, NULL);
return(FALSE);
}
bet_main = betA = atof(bet_str);
return(TRUE);
}
/*
* Main message processing loop. Note: it creates a message port for the
* two windows to share. This way the program can have two windows open
* but only checks for messages at one message port!
*/
VOID doIDCMP(VOID)
{
struct IntuiMessage *imsg;
struct Gadget *work = NULL;
struct Window *temp_win;
struct MenuItem *item;
BOOL done = FALSE, inp = FALSE;
UWORD mnum, inum, snum, code;
ULONG class;
allocDeck();
/* Create a message port and attatch it to the window */
if (!(mport = CreatePort(0,0))) closer();
win->UserPort = mport;
ModifyIDCMP(win,IDCMP_GADGETUP|IDCMP_MENUPICK|IDCMP_CLOSEWINDOW);
if (start_stats) openStatWin();
while (!done) {
Wait(1L << mport->mp_SigBit);
while (imsg = GT_GetIMsg(win->UserPort)) {
class = imsg->Class;
code = imsg->Code;
temp_win = imsg->IDCMPWindow; /* Which window? */
if (class == IDCMP_GADGETUP)
work = (struct Gadget *)imsg->IAddress;
GT_ReplyIMsg(imsg);
if (class == IDCMP_REFRESHWINDOW)
if (stat_win) {
refreshStatWin();
showStats();
}
if (class == IDCMP_CLOSEWINDOW) {
if (temp_win == win) done = TRUE;
else {
safeCloseWin(stat_win);
stat_win = NULL;
Forbid();
ClearMenuStrip(win);
item = strip->FirstItem->NextItem->SubItem;
item->Flags &= ~CHECKED;
item->NextItem->Flags |= CHECKED;
ResetMenuStrip(win, strip);
Permit();
}
}
else if (class == IDCMP_GADGETUP) {
wText("Okay...");
if ((work->GadgetID == DEAL_GAD) && checkBet()){
if ((bank == 0) &&
(putReq("Your broke!","Want a $100 loan?",REQ_ASK))) {
bank = 100;
printBank();
}
else if ((betA > 0) && (betA <= bank)) {
bank -= betA;
printBank();
if (dealt > ((num_decks * A_DECK) - 15))
shuffle();
if (initDeal()) {
if (p_score < 21) {
GAD_OFF(gads[DEAL_GAD]);
GAD_OFF(gads[BET_GAD]);
GAD_ON(gads[HIT_GAD]);
GAD_ON(gads[STICK_GAD]);
if ((bank >= (betA / 2)) && !backcard)
GAD_ON(gads[SUR_GAD]);
if (bank >= betA)
GAD_ON(gads[DD_GAD]);
inp = TRUE;
}
else dealsTurn();
}
}
else if (betA <= 0) {
DisplayBeep(win->WScreen);
wText("You must make a bet first!!");
}
else {
DisplayBeep(win->WScreen);
wText("You don't have enough money.");
}
}
else if (work->GadgetID == BET_GAD)
checkBet();
else if (work->GadgetID == HIT_GAD) {
GAD_OFF(gads[DD_GAD]);
GAD_OFF(gads[SUR_GAD]);
addCard();
if (p_score >= 21) {
if (backcard) {
putReq("Ready for", "second hand...", REQ_OK);
playBack();
}
else {
GAD_OFF(gads[HIT_GAD]);
GAD_OFF(gads[STICK_GAD]);
dealsTurn();
inp = FALSE;
}
}
}
else if (work->GadgetID == STICK_GAD) {
if (backcard) playBack();
else {
GAD_OFF(gads[DD_GAD]);
GAD_OFF(gads[SUR_GAD]);
GAD_OFF(gads[HIT_GAD]);
GAD_OFF(gads[STICK_GAD]);
dealsTurn();
inp = FALSE;
}
}
else if (work->GadgetID == SUR_GAD) {
bank -= betA / 2;
printBank();
p_hand[0] = p_hand[1] = p_score = 0;
p_cord = COL_2 + CARD_WIDTH + 1;
drawCard(deck[dealt], COL_1, P_ROW);
addScore(PLAYER, p_hand);
drawCard(deck[dealt], COL_2, P_ROW);
addScore(PLAYER, p_hand);
if (p_score == 21) {
p_score = 0xFE;
GAD_OFF(gads[DD_GAD]);
GAD_OFF(gads[SUR_GAD]);
GAD_OFF(gads[HIT_GAD]);
GAD_OFF(gads[STICK_GAD]);
dealsTurn();
}
else {
if (bank < (betA / 2)) GAD_OFF(gads[SUR_GAD]);
if (bank < betA) GAD_OFF(gads[DD_GAD]);
}
}
else if(work->GadgetID == DD_GAD) {
GAD_OFF(gads[DD_GAD]);
GAD_OFF(gads[SUR_GAD]);
bank -= betA;
betA += betA;
printBank();
addCard();
if (backcard) {
putReq("Ready for", "second hand...", REQ_OK);
playBack();
}
else {
GAD_OFF(gads[HIT_GAD]);
GAD_OFF(gads[STICK_GAD]);
dealsTurn();
inp = FALSE;
}
}
if (stat_win) showStats();
}
else if (class == IDCMP_MENUPICK) {
mnum = MENUNUM(code);
inum = ITEMNUM(code);
snum = SUBNUM(code);
if (mnum == 0) {
if (!inum) {
t_decks = 1 << snum;
if (t_decks == num_decks) t_decks = 0;
else if (!inp) {
num_decks = t_decks;
t_decks = 0;
allocDeck();
}
}
else if (inum == 1) {
if (!snum) {
if (!stat_win) openStatWin();
}
else {
if (stat_win) {
safeCloseWin(stat_win);
stat_win = NULL;
}
}
}
else if (inum == 3) done = TRUE;
}
}
}
}
return;
}
/*
* Simply prints the players bank
*/
VOID printBank(VOID)
{
UBYTE st[] = {" "};
/* Use floating point notation? */
if (bank > 9999999999999.99) sprintf(st, "Bank: $%-11.2e", bank);
else sprintf(st, "Bank: $%-13.2f", bank);
st[strlen(st)] = 32;
SetAPen(win->RPort, 1);
Move(win->RPort, 10, 150 + win_offset);
Text(win->RPort, st, 19);
return;
}
/*
* Prints players win percentage
*/
VOID printWins(VOID)
{
UBYTE str[] = {" "};
UBYTE perc = 0;
if (hands) perc = 100 * ((FLOAT)winners / (FLOAT)hands);
sprintf(str, "Wins: %d/%d = %d%%", winners, hands, perc);
str[strlen(str)] = 32;
Move(win->RPort, 10, 160 + win_offset);
Text(win->RPort, str, 29);
}
/*
* Updates the decks gauge to refect the amount of cards dealt.
*/
VOID gauge(VOID)
{
LONG offset;
FLOAT per;
per = ((FLOAT)dealt + 1) / ((FLOAT)num_decks * A_DECK);
if (dealt == 0) {
SetAPen(win->RPort, 3);
RectFill(win->RPort, BOX_LEFT, BOX_TOP,
BOX_LEFT + BOX_WIDTH, BOX_TOP + BOX_HEIGHT);
DrawBevelBox(win->RPort, BOX_LEFT, BOX_TOP,
BOX_WIDTH + 1, BOX_HEIGHT + 1,
GT_VisualInfo, vi, TAG_DONE);
return;
}
offset = BOX_WIDTH - ((LONG)(per * BOX_WIDTH));
SetAPen(win->RPort, 0);
RectFill(win->RPort, BOX_LEFT + offset + 1, BOX_TOP,
BOX_LEFT + BOX_WIDTH, BOX_TOP + BOX_HEIGHT);
SetAPen(win->RPort, 1);
Move(win->RPort, BOX_LEFT + offset - 1, BOX_TOP + 1);
Draw(win->RPort, BOX_LEFT + offset - 1, BOX_TOP + BOX_HEIGHT);
Move(win->RPort, BOX_LEFT + offset, BOX_TOP);
Draw(win->RPort, BOX_LEFT + offset, BOX_TOP + BOX_HEIGHT);
return;
}
/*
* Draws a card at x, y (see "jack.h" for the declaration of the Card
* structure and the Image structures).
*/
VOID drawCard(struct Card *c, UWORD x, UWORD y)
{
UBYTE ct;
struct Image *suit;
if (c->Flags & HEARTS) suit = &heart;
else if (c->Flags & DIAMONDS) suit = ⋄
else if (c->Flags & SPADES) suit = &spade;
else suit = &club;
SetAPen(win->RPort, 2);
RectFill(win->RPort, x, y, x+CARD_WIDTH, y+CARD_HEIGHT);
if ((c->Flags & SPADES) || (c->Flags & CLUBS)) SetAPen(win->RPort, 1);
else SetAPen(win->RPort, 3);
SetBPen(win->RPort, 2);
/* Draw the card ID - "2", "3", "4", etc. */
Move(win->RPort, x+1, y+ySize-2);
if (strlen(c->Name) != 2) {
Text(win->RPort, c->Name, 1);
Move(win->RPort, x+52, y+(CARD_HEIGHT-ySize)+7);
Text(win->RPort, c->Name, 1);
}
else {
Text(win->RPort, c->Name, 2);
Move(win->RPort, x+44, y+(CARD_HEIGHT-ySize)+7);
Text(win->RPort, c->Name, 2);
}
/* Draw the suits and face cards (if needed) */
if (c->Face) {
DrawImage(win->RPort, suit, x+11, y+1);
DrawImage(win->RPort, c->Face, x+c->Cords[0],y+c->Cords[1]);
DrawImage(win->RPort, suit, x+40, y+32);
}
else {
for (ct = 0; ct < ((c->Flags & 0xF) * 2); ct += 2)
DrawImage(win->RPort, suit, x+c->Cords[ct],y+c->Cords[ct+1]);
}
SetAPen(win->RPort, 1);
Move(win->RPort, x, y);
Draw(win->RPort, x+CARD_WIDTH, y);
Draw(win->RPort, x+CARD_WIDTH, y+CARD_HEIGHT);
Draw(win->RPort, x, y+CARD_HEIGHT);
Draw(win->RPort, x, y);
gauge();
SetBPen(win->RPort, 0);
if (use_delay) Delay(5);
return;
}
/*
* Allocates memory for the deck. Also, frees memory if the deck already
* existed.
*/
VOID allocDeck(VOID)
{
SetAPen(win->RPort, 0);
RectFill(win->RPort, COL_1, P_ROW, 324, P_ROW + CARD_HEIGHT);
RectFill(win->RPort, COL_1, D_ROW, 324, D_ROW + CARD_HEIGHT);
if (deck) FreeMem(deck, sizeof(struct Card *) * A_DECK * old_decks);
deck = AllocMem(sizeof(struct Card *) * A_DECK * num_decks,
MEMF_ANY | MEMF_CLEAR);
old_decks = num_decks;
shuffle();
return;
}
/*
* This routine is called when a fresh deal is needed. It deals the first
* four cards, checks for Black Jacks and possible splits and insurance
* bets.
*/
BOOL initDeal(VOID)
{
UBYTE s[32], t1;
/* Initialize data */
betB = ins = p_score = d_score = p_score2 = 0;
p_cord = COL_2 + CARD_WIDTH + 1;
backcard = NULL;
for (t1 = 0; t1 < 16; t1++) p_hand[t1] = d_hand[t1] = 0;
/* Erase old cards */
SetAPen(win->RPort, 0);
RectFill(win->RPort, COL_1, P_ROW, 324, P_ROW + CARD_HEIGHT);
RectFill(win->RPort, COL_1, D_ROW, 324, D_ROW + CARD_HEIGHT);
drawCard(deck[dealt], COL_1, P_ROW);
addScore(PLAYER, p_hand);
drawCard(deck[dealt], COL_1, D_ROW);
addScore(DEALER, d_hand);
drawCard(deck[dealt], COL_2, P_ROW);
addScore(PLAYER, p_hand);
if (p_score == 21) p_score = 0xFE;
/* Dealer has an Ace */
if ((d_hand[0] == 1) && (p_score != 0xFE) && (bank >= (betA / 2))) {
if (putReq("Would you like", "an Insurance bet?", REQ_ASK)) {
ins = betA / 2;
bank -= ins;
printBank();
if (ins > 9999999999999.99)
sprintf(s, "Insurance bet = $%11.2e", ins);
else
sprintf(s, "Insurance bet = $%.2f", ins);
wText(s);
}
}
DrawImage(win->RPort, &hole, COL_2, D_ROW);
hole_card = deck[dealt++];
/* Dealer has Black Jack */
if ((((hole_card->Flags & MASK) == 0x1) && (d_score == 10)) ||
(((hole_card->Flags & MASK) > 0x9) && (d_score == 11))) {
drawCard(hole_card, COL_2, D_ROW);
addScore(FIRST, d_hand);
d_score = 0xFE;
printScore();
if (ins) bank += ins * 3;
if (p_score == 0xFE) {
wText("We both have Black Jack!");
bank += betA;
}
else {
if (ins) wText("At least you won the insurance!");
else wText("Black Jack! You lose!!");
}
printBank();
hands++;
printWins();
return(FALSE);
}
/* Player can split */
if ((deck[dealt-2]->Flags & MASK) == (deck[dealt-4]->Flags & MASK)) {
if (bank >= betA) {
if (putReq("Do you", "want to Split?", REQ_ASK)) {
backcard = deck[dealt-2];
if (p_hand[1] == 1) p_score -= 11;
else p_score -= p_hand[1];
p_hand[1] = 0;
printScore();
drawCard(deck[dealt], COL_2, P_ROW);
addScore(PLAYER, p_hand);
bank -= betA;
printBank();
GAD_OFF(gads[SUR_GAD]);
wText("Playing first hand...");
if (p_score == 21) {
p_score = 0xFE;
putReq("First hand is", "a Black Jack!", REQ_OK);
playBack();
if (p_score == 0xFE) return(FALSE); /* 2 BJacks! */
}
}
}
}
return(TRUE);
}
/*
* Deciphers the point value of a card from its Flags.
*/
VOID addScore(UBYTE who, UBYTE *array)
{
UBYTE score, i, hard = 0, aces = 0;
if (who == FIRST) score = hole_card->Flags & MASK;
else if (who == BACK) score = backcard->Flags & MASK;
else score = deck[dealt]->Flags & MASK;
if (score == 0x1) {
aces++;
if (who == PLAYER) p_crd[12]++;
else if (who != BACK) d_crd[12]++;
}
else {
if (who == PLAYER) p_crd[score - 2]++;
else if (who != BACK) d_crd[score - 2]++;
}
if (score > 0x9) score = 0xA;
for (i = 0; i < 16; i++) {
if (array[i] == 0) break;
if (array[i] != 1) hard += array[i];
else {
hard += 11;
aces++;
}
}
array[i] = score;
if (score == 1) hard += 11;
else hard += score;
for (i = 0; i < aces; i++) {
if (hard <= 21) break;
else hard -= 10;
}
if (who == PLAYER) p_score = hard;
else if (who != BACK) d_score = hard;
if ((who != FIRST) && (who != BACK)) dealt++;
printScore();
return;
}
/*
* The player wants another card
*/
VOID addCard(VOID)
{
drawCard(deck[dealt], p_cord, P_ROW);
addScore(PLAYER, p_hand);
if (p_cord >= 254) p_cord -= 225;
else p_cord += 61;
return;
}
/*
* Prints both scores. If score == 0xFE its a Black Jack
*/
VOID printScore(VOID)
{
UBYTE s1[3], s2[3];
if (p_score == 0xFE) strcpy(s1, "BJ");
else sprintf(s1, "%2d", p_score);
if (d_score == 0xFE) strcpy(s2, "BJ");
else sprintf(s2, "%2d", d_score);
SetAPen(win->RPort, 2);
Move(win->RPort, 50, 123 + win_offset);
Text(win->RPort, s1, 2);
Move(win->RPort, 50, 133 + win_offset);
Text(win->RPort, s2, 2);
return;
}
/*
* The dealer takes his cards and determines the winner and payoffs
*/
VOID dealsTurn(VOID)
{
UWORD d_cord;
BOOL okay = TRUE;
BYTE h1 = 0, h2 = 0, say[32], *res[] = {"Won", "Lost", "Push"};
d_cord = COL_2 + CARD_WIDTH + 1;
drawCard(hole_card, COL_2, D_ROW);
addScore(FIRST, d_hand);
if (d_score >= 17) okay = FALSE;
while (okay) {
drawCard(deck[dealt], d_cord, D_ROW);
addScore(DEALER, d_hand);
if (d_cord >= 254) d_cord -= 225;
else d_cord += 61;
if (d_score >= 17) okay = FALSE;
}
if (p_score == 0xFE) { /* Black Jack */
bank += betA * 2.5;
p_score = 21;
wText("You win with Black Jack!!");
winners++;
}
else if (p_score > 21) { /* Player tap */
wText("You've tapped out.");
h1 = 1;
}
else if (d_score > 21) { /* Dealer Tap */
bank += betA * 2;
wText("Dealer tapped - You win!");
winners++;
}
else if (p_score == d_score) { /* Push */
bank += betA;
wText("It's a Push - No winners");
h1 = 2;
}
else if (p_score > d_score) { /* Winner */
bank += betA * 2;
wText("You win!!");
winners++;
}
else { /* d_score > p_score */
wText("The Dealer wins.");
h1 = 1;
}
if (p_score2) { /* Player split */
hands++;
if (p_score2 == 0xFE) { /* Black Jack */
bank += betB * 2.5;
p_score2 = 21;
winners++;
}
else if (p_score2 > 21) /* Player tap */
h2 = 1;
else if (d_score > 21) { /* Dealer tap */
bank += betB * 2;
winners++;
}
else if (p_score2 == d_score) { /* Push */
h2 = 2;
bank += betB;
}
else if (p_score2 > d_score) { /* Player wins */
bank += betB * 2;
winners++;
}
else /* Player tap and */
h2 = 1; /* d_score > p_score2 */
sprintf(say, "%s: %d <> %s: %d", res[h2],p_score2,res[h1],p_score);
wText(say);
}
printBank();
hands++;
printWins();
if (t_decks) { /* Check to see if player changed the */
num_decks = t_decks; /* number od decks while the hand was */
t_decks = 0; /* in progress. */
allocDeck();
}
GAD_ON(gads[BET_GAD]);
GAD_ON(gads[DEAL_GAD]);
return;
}
/*
* Centers a string and prints it
*/
VOID wText(UBYTE *s)
{
UBYTE len;
UWORD offs;
struct TextExtent texex;
len = strlen(s);
SetAPen(win->RPort,0);
RectFill(win->RPort, 7, 51 + win_offset, 323, 60 + win_offset);
SetAPen(win->RPort, 1);
Move(win->RPort, 0, 0);
TextExtent(win->RPort, s, len, &texex);
offs = 5 + ((322 - texex.te_Extent.MaxX) / 2);
Move(win->RPort, offs, 58 + win_offset);
Text(win->RPort, s, len);
return;
}
/*
* The player has 'Split'
*/
VOID playBack(VOID)
{
UBYTE i;
p_cord = COL_2 + CARD_WIDTH;
SetAPen(win->RPort, 0);
RectFill(win->RPort, COL_1, P_ROW, 324, P_ROW + CARD_HEIGHT);
GAD_ON(gads[DD_GAD]);
GAD_OFF(gads[SUR_GAD]);
p_score2 = p_score;
p_score = 0;
betB = betA;
betA = bet_main;
for (i = 0; i < 16; i++) p_hand[i] = 0;
wText("Playing second hand, now...");
drawCard(backcard, COL_1, P_ROW);
addScore(BACK, p_hand);
drawCard(deck[dealt], COL_2, P_ROW);
addScore(PLAYER, p_hand);
backcard = NULL;
if (p_score == 21) {
p_score = 0xFE;
GAD_OFF(gads[DD_GAD]);
GAD_OFF(gads[HIT_GAD]);
GAD_OFF(gads[STICK_GAD]);
dealsTurn();
}
return;
}
/*
* Open the Statistics window
*/
VOID openStatWin(VOID)
{
UWORD xwin;
WORD wzoom[] = {0,0,130,0};
if ((win->LeftEdge + 332) > (win->WScreen->Width - 130))
xwin = win->LeftEdge - 130;
else xwin = win->LeftEdge + 332;
wzoom[0] = xwin;
wzoom[1] = win->TopEdge;
wzoom[3] = win_offset;
if (!(stat_win = OpenWindowTags(NULL,
WA_Left, xwin,
WA_Top, win->TopEdge,
WA_Width, 130,
WA_Height, 166 + win_offset,
WA_CloseGadget, TRUE,
WA_DepthGadget, TRUE,
WA_Zoom, wzoom,
WA_DragBar, TRUE,
WA_IDCMP, NULL,
WA_SmartRefresh,TRUE,
WA_RMBTrap, TRUE,
WA_PubScreen, win->WScreen,
WA_ScreenTitle, win->ScreenTitle,
WA_Title, "Stats",
TAG_END)))
return;
if (wFont) SetFont(stat_win->RPort, wFont);
stat_win->UserPort = mport;
ModifyIDCMP(stat_win, IDCMP_CLOSEWINDOW|IDCMP_REFRESHWINDOW);
refreshStatWin();
showStats();
return;
}
/*
* Since the two windows share an IDCMP port, must make sure that there
* are no more messages for that window before trying to close it.
*/
VOID safeCloseWin(struct Window *w)
{
struct IntuiMessage *msg;
struct Node *succ;
Forbid();
msg = (struct IntuiMessage *)mport->mp_MsgList.lh_Head;
while(succ = msg->ExecMessage.mn_Node.ln_Succ) {
if (msg->IDCMPWindow == w) {
Remove((struct Node *)msg);
ReplyMsg((struct Message *)msg);
}
msg = (struct IntuiMessage *)succ;
}
w->UserPort = NULL;
ModifyIDCMP(w, NULL);
Permit();
CloseWindow(w);
return;
}
/*
* Redraw the Statistics window graphics
*/
VOID refreshStatWin(VOID)
{
static UBYTE *sc[] = {
" 2", " 3", " 4", " 5", " 6", " 7", " 8", " 9",
"10", " J", " Q", " K", " A"
};
static UBYTE title[] = {" P D %"};
UBYTE row = 22, col = 7, x;
if (!stat_win) return;
SetAPen(stat_win->RPort, 3);
RectFill(stat_win->RPort, 4, win_offset, 125, 162 + win_offset);
SetAPen(stat_win->RPort, 0);
RectFill(stat_win->RPort, 28, 13 + win_offset, 117, 146 + win_offset);
DrawBevelBox(stat_win->RPort, 28, 13 + win_offset, 89 + 1, 133 + 1,
GT_VisualInfo, vi, TAG_END);
SetAPen(stat_win->RPort, 1);
SetDrMd(stat_win->RPort, JAM1);
Move(stat_win->RPort, 6, 9 + win_offset);
Text(stat_win->RPort, title, 13);
SetAPen(stat_win->RPort, 2);
Move(stat_win->RPort, 4, 8 + win_offset);
Text(stat_win->RPort, title, 13);
SetAPen(stat_win->RPort, 1);
for (x = 0; x < 13; x++) {
Move(stat_win->RPort, col, row + win_offset);
Text(stat_win->RPort, sc[x], 2);
row += 10;
}
row = 21; col = 5;
SetAPen(stat_win->RPort, 2);
for (x = 0; x < 13; x++) {
Move(stat_win->RPort, col, row + win_offset);
Text(stat_win->RPort, sc[x], 2);
row += 10;
}
SetDrMd(stat_win->RPort, JAM2);
return;
}
/*
* My own version of EasyRequest(). I use Nico Franτois' RT_Patch - it
* puts all system requesters at the pointer. I am emulating that
* here for people who don't have RT_Patch
*/
BOOL putReq(UBYTE *stra, UBYTE *strb, BYTE flag)
{
struct IntuiMessage *im;
struct Window *req_win;
BOOL done = FALSE, ans;
WORD le, te, gl, offa, offb, lena, lenb, left_off = 100;
struct Gadget *rgad, *rlist;
struct NewGadget rng;
struct Requester req;
struct TextExtent texe;
gl = (flag) ? 10 : 51;
rgad = CreateContext(&rlist);
rng.ng_LeftEdge = gl;
rng.ng_TopEdge = 28 + win_offset;
rng.ng_Width = 80;
rng.ng_Height = 14;
rng.ng_GadgetText = "Okay";
rng.ng_TextAttr = &Topaz80;
rng.ng_GadgetID = 1;
rng.ng_Flags = NULL;
rng.ng_VisualInfo = vi;
rng.ng_UserData = NULL;
rgad = CreateGadget(BUTTON_KIND, rgad, &rng, TAG_END);
if (flag) {
left_off = 137;
rng.ng_LeftEdge = 95;
rng.ng_GadgetText = "Cancel";
rng.ng_GadgetID = 0;
rgad = CreateGadget(BUTTON_KIND, rgad, &rng, TAG_END);
}
InitRequester(&req);
Request(&req, win);
le = ((win->MouseX + win->LeftEdge) < left_off) ? 0 :
(win->MouseX + win->LeftEdge - left_off);
te = ((win->MouseY + win->TopEdge) < 47) ? 0 :
(win->MouseY + win->TopEdge - 47);
if (req_win = OpenWindowTags(NULL,
WA_Left, le,
WA_Top, te,
WA_Width, 182,
WA_Height, 45 + win_offset,
WA_Gadgets, rlist,
WA_IDCMP, IDCMP_GADGETUP,
WA_DepthGadget, TRUE,
WA_DragBar, TRUE,
WA_Activate, TRUE,
WA_RMBTrap, TRUE,
WA_Title, "Jack Note:",
WA_ScreenTitle, win->ScreenTitle,
WA_PubScreen, win->WScreen,
TAG_END)) {
if (wFont) SetFont(req_win->RPort, wFont);
DrawBevelBox(req_win->RPort, 9, 2 + win_offset, 166,
10 + win_offset, GT_VisualInfo, vi,
GTBB_Recessed, TRUE, TAG_END);
lena = strlen(stra);
lenb = strlen(strb);
SetAPen(req_win->RPort, 1);
Move(req_win->RPort, 0, 0);
TextExtent(req_win->RPort, stra, lena, &texe);
offa = (182 - texe.te_Extent.MaxX) / 2;
Move(req_win->RPort, offa, 11 + win_offset);
Text(req_win->RPort, stra, lena);
Move(req_win->RPort, 0, 0);
TextExtent(req_win->RPort, strb, lenb, &texe);
offb = (182 - texe.te_Extent.MaxX) / 2;
Move(req_win->RPort, offb, 20 + win_offset);
Text(req_win->RPort, strb, lenb);
while (!done) {
Wait(1L << req_win->UserPort->mp_SigBit);
while (im = (struct IntuiMessage *)GetMsg(req_win->UserPort)) {
if (im->Class == IDCMP_GADGETUP) {
ans = ((struct Gadget *)im->IAddress)->GadgetID;
done = TRUE;
}
ReplyMsg((struct Message *)im);
}
}
CloseWindow(req_win);
}
FreeGadgets(rlist);
EndRequest(&req, win);
return(ans);
}